const MAX_FILENAME_LEN  = 500;
const MAX_BLOCK_SIZE    = 512;
const MAX_ERRSTR_LEN    = 100;

typedef string filename_t<MAX_FILENAME_LEN>;
typedef opaque block_t<MAX_BLOCK_SIZE>;
typedef string errstr_t<MAX_ERRSTR_LEN>;

enum mode_t {
  OCTET,
  TEXT
};

enum errcode_t {
  NOT_DEFINED         = 0x00,
  FILE_NOT_FOUND      = 0x01,
  ACCESS_VIOLATION    = 0x02,
  DISK_FULL           = 0x03,
  ILL_OP_TFTP         = 0x04,
  UNKNOWN_PORT        = 0x05,
  FILE_ALREADY_EXISTS = 0x06,
  NO_SUCH_USER        = 0x07
};


struct req_t {
  filename_t filename;
  mode_t mode;
};

struct err_t {
  errcode_t errcode;
  errstr_t errstr;
};

union maybe_t switch (bool ok) {
  case TRUE:  void;
  case FALSE: err_t err;
};

union maybe_block_t switch (bool ok) {
  case TRUE:  block_t block;
  case FALSE: err_t err;
};


program TFTP {

  version TFTP_VERSION {

    maybe_t       GET(req_t req)                = 1;
    maybe_t       PUT(req_t req)                = 2;
    maybe_block_t GET_BLOCK(void)               = 3;
    maybe_t       PUT_BLOCK(block_t block)      = 4;
    void          ERROR(err_t err)              = 5;

  } = 1;

} = 0x2DDE7BB4;

